import hashlib
import inspect
import json
import os
import random
import re

from requests import Session

from core.spider import BaseSpider

BASE_DIR = os.path.dirname(__file__)


def write_json(res):
    with open(BASE_DIR + '/json/' + inspect.stack()[1][3] + '.json', 'w', encoding='utf8') as f:
        f.write(json.dumps(res, ensure_ascii=False))


class Spider(BaseSpider):
    NAME = 'xiami'

    # 分类歌单的对应ID
    # 华语(1)、欧美(2)、韩语(3)、日语(4)、流行(5)、纯音乐(5)、摇滚(7)、电子(8)、民谣(9)
    # 分类: 原本分类
    SONGS_LIST_CATEGORY_ID = {
        1: "华语",
        2: "欧美",
        3: "韩语",
        4: "日语",
        5: "流行",
        6: "纯音乐",
        7: "摇滚",
        8: "电子",
        9: "民谣",
    }
    # 排行榜对应的ID
    # 飙升(1)、新歌(2)、热歌(3)、原创(4)、抖音(5)
    TOP_LIST_ID = {
        1: 305,
        2: 102,
        3: 103,
        4: 104,
        5: 332,
    }


    def __init__(self):
        super().__init__()
        self.DOMAIN = "https://www.xiami.com"
        self.session.get(self.DOMAIN)


    def _params(self, _url, _q=''):
        r = self.session.cookies.get('xm_sg_tk', None).split('_')[0]
        md5 = hashlib.md5()
        md5.update(f"{r}_xmMain_{_url}_{_q}".encode())
        return md5.hexdigest()


    def get_recommend_songs_list(self):
        """
        推荐歌单
        :return:
        """
        url = '/api/collect/getCollects'
        data = json.dumps({"limit": 10, "order": "recommend", "page": 1})
        params = {
            '_q': data,
            '_s': self._params(url, data)
        }
        res = self.session.get(self.DOMAIN + url, params=params).json()
        assert res['code'] == "SUCCESS", f"获取推荐歌单失败\n返回数据：{res}"
        if __name__ == '__main__':
            write_json(res)
        return self.return_res(res)


    def get_recommend_songs(self):
        """
        推荐歌曲
        :return:
        """
        url = '/api/recommend/getDailySongs'
        params = {
            '_s': self._params(url),
        }
        res = self.session.get(self.DOMAIN + url, params=params).json()
        assert res['code'] == "SUCCESS", f"获取推荐歌曲失败\n返回数据：{res}"
        if __name__ == '__main__':
            write_json(res)
        return self.return_res(res)


    def get_songs_list_by_category(self, category_id):
        """
        分类歌单
        :param category_id:
        :return:
        """
        url = '/api/list/collect'
        data = json.dumps({"dataType": "system", "key": f"{category_id}", "pagingVO": {"page": 1, "pageSize": 10}})
        params = {
            '_q': data,
            '_s': self._params(url, data),
        }
        res = self.session.get(self.DOMAIN + url, params=params).json()
        assert res['code'] == "SUCCESS", f"获取推荐歌曲失败\n返回数据：{res}"
        if __name__ == '__main__':
            write_json(res)
        return self.return_res(res)


    def get_songs_list_detail(self, list_id):
        """
        歌单详情
        :param list_id:
        :return:
        """
        url = '/api/collect/initialize'
        data = json.dumps({"listId": list_id})
        params = {
            '_q': data,
            '_s': self._params(url, data),
        }
        res = self.session.get(self.DOMAIN + url, params=params).json()
        assert res['code'] == "SUCCESS", f"获取歌单详情失败\n返回数据：{res}"
        if __name__ == '__main__':
            write_json(res)
        return self.return_res(res)


    def get_song_detail(self, song_mid):
        """
        歌曲详情
        :return:
        """
        url = '/api/song/initialize'
        data = json.dumps({"songId": song_mid})
        params = {
            '_q': data,
            '_s': self._params(url, data),
        }
        res = self.session.get(self.DOMAIN + url, params=params).json()
        assert res['code'] == "SUCCESS", f"获取歌曲详情失败\n返回数据：{res}"
        if __name__ == '__main__':
            write_json(res)
        return self.return_res(res)


    def get_song_play_url(self, song_mid):
        """
        歌曲播放地址
        :return:
        """
        url = '/api/song/getPlayInfo'
        data = json.dumps({"songIds": [song_mid]})
        params = {
            '_q': data,
            '_s': self._params(url, data),
        }
        res = self.session.get(self.DOMAIN + url, params=params).json()
        assert res['code'] == "SUCCESS", f"获取歌曲播放地址失败\n返回数据：{res}"
        if __name__ == '__main__':
            write_json(res)
        return self.return_res(res)


    def get_song_lyric(self, song_id):
        """
        歌词
        :return:
        """
        url = '/api/lyric/getSongLyrics'
        data = json.dumps({"songId": song_id})
        params = {
            '_q': data,
            '_s': self._params(url, data),
        }
        res = self.session.get(self.DOMAIN + url, params=params).json()
        assert res['code'] == "SUCCESS", f"获取歌词失败\n返回数据：{res}"
        if __name__ == '__main__':
            write_json(res)
        return self.return_res(res)


    def get_mv_play_url(self, vid):
        """
        mv
        :param vid:
        :return:
        """

        def _get_url(m3u8_url):
            res = self.session.get(m3u8_url)
            if res.status_code == 200:
                reg = r'http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+'
                return re.findall(reg, res.text)

        url = '/api/mv/initialize'
        data = json.dumps({"mvId": vid})
        params = {
            '_q': data,
            '_s': self._params(url, data),
        }
        res = self.session.get(self.DOMAIN + url, params=params).json()
        assert res['code'] == "SUCCESS", f"获取MV失败\n返回数据：{res}"
        detail = res['result']['data']['detail']['mvDetailVO']
        # 有没有其他品质视频的m3u8
        m3u8_list = _get_url(detail['url'])
        res = detail['mp4Url'] if not m3u8_list else m3u8_list
        if __name__ == '__main__':
            write_json(res)
        return self.return_res(res)


    def get_top_list(self, top_id):
        """
        排行榜
            新歌榜：102
            热歌榜：103
            原创榜：104
            K歌榜：360
            抖音榜：332
            歌单收录榜：305
            趴间热歌榜：327
            分享榜：307
            影视榜：324
            原创榜：104
            原创榜：104
            原创榜：104
        :param top_id:
        :return:
        """
        url = '/api/billboard/getBillboardDetail'
        data = json.dumps({"billboardId": top_id})
        params = {
            '_q': data,
            '_s': self._params(url, data),
        }
        res = self.session.get(self.DOMAIN + url, params=params).json()
        assert res['code'] == "SUCCESS", f"获取排行榜失败\n返回数据：{res}"
        if __name__ == '__main__':
            write_json(res)
        return self.return_res(res)


    def get_search_song(self, kw):
        """
        搜索: 频率限制
        :param kw:
        :return:
        """
        url = '/api/search/searchSongs'
        data = json.dumps({"key": f"{kw}", "pagingVO": {"page": 1, "pageSize": 10}})
        params = {
            '_q': data,
            '_s': self._params(url, data),
        }
        res = self.session.get(self.DOMAIN + url, params=params).json()
        hasattr(res, 'code')
        assert res['code'] == "SUCCESS", f"搜索失败\n返回数据：{res}"
        if __name__ == '__main__':
            write_json(res)
        return self.return_res(res)


if __name__ == '__main__':
    # req = Session()
    # req.get('https://www.xiami.com')
    # url = '/api/collect/getCollects'
    # _q = json.dumps({"limit": 20, "order": "recommend", "page": 1})
    # r = req.cookies.get('xm_sg_tk', None).split('_')[0]
    # md5 = hashlib.md5()
    # md5.update(f"{r}_xmMain_{url}_{_q}".encode())
    # _s = md5.hexdigest()
    # params = {
    #     '_q': _q,
    #     '_s': _s,
    # }
    # res = req.get('https://www.xiami.com' + url, headers=headers, params=params)
    # print(res.json()['result']['data']['collects'])

    xiami = Spider()
    xiami.get_recommend_songs_list()
    # xiami.get_recommend_songs()
    # xiami.get_songs_list_by_category("华语")
    # xiami.get_song_list_detail(48102083)
    # xiami.get_song_detail("mSFWBO804da")
    # xiami.get_song_play_url("mSFWBO804da")
    # xiami.get_song_lyric(1801512872)
    # xiami.get_mv_play_url('K6Y48E')
    # xiami.get_top_list(332)
